package com.have.blog.web.service.impl;

import com.have.blog.base.dto.SystemConfigDto;
import com.have.blog.base.enums.BlogOpenStatus;
import com.have.blog.base.enums.BlogStatus;
import com.have.blog.base.wrapper.ResultCode;
import com.have.blog.base.wrapper.Wrapper;
import com.have.blog.config.hloder.RequestHolder;
import com.have.blog.model.mapper.UserMapper;
import com.have.blog.model.models.User;
import com.have.blog.model.models.UserExample;
import com.have.blog.picture.service.PictureFeignApi;
import com.have.blog.utils.IpUtils;
import com.have.blog.utils.MyBeanUtils;
import com.have.blog.utils.StringUtils;
import com.have.blog.web.bo.LoginInfo;
import com.have.blog.web.bo.WebUserDetail;
import com.have.blog.web.constant.BlogConstant;
import com.have.blog.web.dto.LoginDto;
import com.have.blog.web.dto.RegisterDto;
import com.have.blog.web.dto.UpdatePwdDto;
import com.have.blog.web.dto.UserDto;
import com.have.blog.web.redis.UserRedisService;
import com.have.blog.web.service.SystemConfigService;
import com.have.blog.web.service.UserService;
import com.have.blog.web.service.WebConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Service
@SuppressWarnings("all")
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WebConfigService webConfigService;
    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private UserRedisService userRedisService;
    @Autowired
    private PictureFeignApi pictureFeignApi;

    @Override
    public Wrapper register(RegisterDto registerDto) {
        Boolean openLoginFlag = webConfigService.isOpenLoginType("PASSWORD");
        if (!openLoginFlag) {
            return Wrapper.failed("未开启注册功能");
        }
        String email = registerDto.getEmail();
        String nickname = registerDto.getNickname();
        String password = registerDto.getPassword();
        String username = registerDto.getUsername();

        HttpServletRequest request = RequestHolder.getRequest();
        String ipAddr = IpUtils.getIpAddr(request);
        Map<String, String> map = IpUtils.getOsAndBrowserInfo(request);

        UserExample example = new UserExample();
        example.createCriteria()
                .andStatusEqualTo(BlogStatus.ENABLE.getStatus())
                .andUsernameEqualTo(username);
        long count = userMapper.countByExample(example);
        if (count > 0) {
            return Wrapper.failed("用户名重复");
        }
        example.createCriteria()
                .andStatusEqualTo(BlogStatus.ENABLE.getStatus())
                .andEmailEqualTo(email);
        count = userMapper.countByExample(example);
        if (count > 0) {
            return Wrapper.failed("邮箱重复");
        }

        User user = new User();
        user.setEmail(email);
        user.setUsername(username);
        user.setNickname(nickname);
        user.setPassword(password); // TODO 密码加密
        user.setSource("YUEQIAN");
        user.setLastLoginIp(ipAddr);
        user.setBrowser(map.get(BlogConstant.BROWSER));
        user.setOs(map.get(BlogConstant.OS));

        SystemConfigDto config = systemConfigService.getConfig();
        String openEmailActivate = config.getOpenEmailActivate();
        if (BlogOpenStatus.OPEN.equals(openEmailActivate)) {
            user.setStatus(BlogStatus.FREEZE.getStatus());
        } else {
            user.setStatus(BlogStatus.ENABLE.getStatus());
        }
        int result = userMapper.insertSelective(user);

        if (result > 0) {
            // rabbitMQ 发送邮件
            return Wrapper.successWithMessage("注册成功");
        }
        return Wrapper.failed("注册失败，请重试");
    }

    @Override
    public Wrapper login(LoginDto loginDto) {
        String loginType = "PASSWORD";
        boolean flag = webConfigService.isOpenLoginType(loginType);
        if (!flag) {
            return Wrapper.failed("后台未开启该登录方式");
        }
        String userName = loginDto.getUsername();
        String email = loginDto.getEmail();
        String passWord = loginDto.getPassword();
        UserExample example = new UserExample();
        UserExample.Criteria criteria1 = example.createCriteria()
                .andStatusEqualTo(BlogStatus.ENABLE.getStatus())
                .andUsernameEqualTo(userName);
        if (!StringUtils.isEmpty(email)) {
            UserExample.Criteria criteria2 = example.createCriteria()
                    .andStatusEqualTo(BlogStatus.ENABLE.getStatus())
                    .andEmailEqualTo(email);
            example.or(criteria2);
        }
        List<User> users = userMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(users)) {
            return Wrapper.failed("用户不存在");
        }
        User user = users.get(0);
        if (BlogStatus.FREEZE.getStatus() == user.getStatus()) {
            return Wrapper.failed("账号被冻结");
        }

        WebUserDetail userDetail = new WebUserDetail(user);
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetail, null, null);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        if (!StringUtils.isEmpty(passWord) && user.getPassword().equals(passWord)) {
            HttpServletRequest request = RequestHolder.getRequest();
            String ipAddr = IpUtils.getIpAddr(request);
            Map<String, String> osAndBrowserInfo = IpUtils.getOsAndBrowserInfo(request);
            user.setBrowser(osAndBrowserInfo.get("BROWSER"));
            user.setOs(osAndBrowserInfo.get("OS"));
            user.setLastLoginIp(ipAddr);
            user.setLastLoginTime(new Date());
            user.setPassword(null);

            userMapper.updateByPrimaryKeySelective(user);
            String token = StringUtils.getUUID();
            userRedisService.addUserByToken(token, user);
            log.info("账号密码登录成功，返回token:{}", token);
            return Wrapper.success(token);
        }
        return Wrapper.failed(ResultCode.LOGIN_ERROR.getCode(), "用户名或密码错误");
    }

    @Override
    public Map<Integer, UserDto> getUserByUids(List<Integer> userIds) {
        Map<Integer, UserDto> map = new HashMap<>();
        if (CollectionUtils.isEmpty(userIds)) {
            return map;
        }
        UserExample example = new UserExample();
        example.createCriteria()
                .andUidIn(userIds)
                .andStatusEqualTo(BlogStatus.ENABLE.getStatus());
        List<User> userList = userMapper.selectByExample(example);
        List<UserDto> resultList = MyBeanUtils.copyListProperties(userList, UserDto::new);
        addPhoto(resultList);
        for (UserDto userDto : resultList) {
            map.put(userDto.getUid(), userDto);
        }
        return map;
    }

    private void addPhoto(List<UserDto> userDtoList) {
        if (CollectionUtils.isEmpty(userDtoList)) {
            return;
        }
        List<Integer> picUids = new ArrayList<>();
        userDtoList.forEach(item -> {
            if (item.getHeadUid() != null) {
                picUids.add(item.getHeadUid());
            }
        });
        if (!CollectionUtils.isEmpty(picUids)) {
            Wrapper<Map<Integer, String>> wrapper = pictureFeignApi.getPicturesUrl(picUids);
            if (wrapper.isSuccess()) {
                Map<Integer, String> picMap = wrapper.getData();
                for (UserDto userDto : userDtoList) {
                    userDto.setPhotoUrl(picMap.get(userDto.getHeadUid()));
                }
            }
        }
    }

    @Override
    public UserDto getUserByUid(Integer uid) {
        User user = userMapper.selectByPrimaryKey(uid);
        if (user == null) {
           return new UserDto();
        }
        UserDto userDto = MyBeanUtils.copyProperties(user, UserDto::new);
        if (user.getHeadUid() != null) {
            Wrapper<String> wrapper = pictureFeignApi.getPictureUrl(user.getHeadUid());
            if (wrapper.isSuccess()) {
                userDto.setPhotoUrl(wrapper.getData());
            }
        }
        return userDto;
    }

    @Override
    public Wrapper editUser(UserDto userDto) {
        Integer uid = userDto.getUid();
        Integer userUid = RequestHolder.getUserUid();
        if (userUid != userUid) {
            return Wrapper.unauthorized();
        }
        User user = userMapper.selectByPrimaryKey(uid);
        if (user == null) {
            return Wrapper.illegal();
        }
        user.setUid(userDto.getUid());
        user.setNickname(userDto.getNickname());
        user.setHeadUid(userDto.getHeadUid());
        user.setGender(userDto.getGender());
        user.setOccupation(userDto.getOccupation());
        user.setSummary(userDto.getSummary());
        user.setQqNumber(userDto.getQqNumber());
        user.setBirthday(userDto.getBirthday());
        user.setStartEmailNotification(userDto.getStartEmailNotification());
        int update = userMapper.updateByPrimaryKeySelective(user);
        if (update > 0) {
            return Wrapper.success(user);
        }
        return Wrapper.failed();
    }

    @Override
    public Wrapper updatePwd(UpdatePwdDto updatePwdDto) {
        Integer userUid = RequestHolder.getUserUid();
        User user = userMapper.selectByPrimaryKey(userUid);
        if (!user.getPassword().equals(updatePwdDto.getOldPwd())) {
            return Wrapper.failed("密码错误");
        }
        user.setPassword(updatePwdDto.getNewPwd());
        int update = userMapper.updateByPrimaryKeySelective(user);
        if (update > 0) {
            return Wrapper.success();
        }
        return Wrapper.failed();
    }

    @Override
    public Wrapper logout(String token) {
        userRedisService.delUserByToken(token);
        return Wrapper.success();
    }
}
